package com.foton.lotteryapplication.process.service.impl;

import com.foton.lotteryapplication.mq.producer.LotteryKafkaProducer;
import com.foton.lotteryapplication.process.req.DrawProcessReq;
import com.foton.lotteryapplication.process.res.DrawProcessResult;
import com.foton.lotteryapplication.process.res.RuleQuantificationCrowdResult;
import com.foton.lotteryapplication.process.service.IActivityProcess;
import com.foton.lotterycommon.common.Constants;
import com.foton.lotterycommon.common.Result;
import com.foton.lotterydomain.activity.model.req.PartakeReq;
import com.foton.lotterydomain.activity.model.res.PartakeRes;
import com.foton.lotterydomain.activity.model.vo.DrawOrderVO;
import com.foton.lotterydomain.activity.model.vo.InvoiceVO;
import com.foton.lotterydomain.activity.service.partake.IActivityPartake;
import com.foton.lotterydomain.rule.model.req.DecisionMatterReq;
import com.foton.lotterydomain.rule.model.res.EngineResult;
import com.foton.lotterydomain.rule.service.engine.EngineFilter;
import com.foton.lotterydomain.strategy.model.req.DrawReq;
import com.foton.lotterydomain.strategy.model.res.DrawResult;
import com.foton.lotterydomain.strategy.model.vo.DrawAwardInfo;
import com.foton.lotterydomain.strategy.service.draw.IDrawExec;
import com.foton.lotterydomain.support.ids.IdGenerator;
import org.springframework.kafka.support.SendResult;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.util.concurrent.ListenableFutureCallback;

import javax.annotation.Resource;
import java.util.Map;

/**
 * @Author RenPu
 * @Date 2024/1/3 11:53
 * @Version 1.0
 * @Description:
 **/

@Component
public class IActivityProcessImpl implements IActivityProcess {

    @Resource
    private IActivityPartake iActivityPartake;   //活动领取领域

    @Resource
    private IDrawExec iDrawExec;    //抽奖领域

    @Resource
    private EngineFilter engineFilter;

    @Resource
    private LotteryKafkaProducer lotteryKafkaProducer;


    @Resource
    private Map<Constants.Ids, IdGenerator> idGeneratorMap; //ID生成策略支持领域

    @Override
    public DrawProcessResult doDrawProcess(DrawProcessReq req) {

        //活动领取
        PartakeRes partakeRes = iActivityPartake.doPartake(new PartakeReq(Long.parseLong(req.getuId()), req.getActivityId()));
        if(!Constants.ResponseCode.SUCCESS.getCode().equals(partakeRes.getCode())){
            return new DrawProcessResult(partakeRes.getCode(),partakeRes.getInfo());
        }

        Long strategyId = partakeRes.getStrategyId();
        Long takeId = partakeRes.getTakeId();


        //执行抽奖
        DrawResult drawResult = iDrawExec.doIDrawExec(new DrawReq(req.getuId(), strategyId, takeId));
        if(Constants.DrawState.FAIL.getCode().equals(drawResult.getDrawState())){
            return  new DrawProcessResult(Constants.ResponseCode.LOSING_DRAW.getCode(),Constants.ResponseCode.LOSING_DRAW.getInfo());
        }


        //落库保存 抽奖结果
        DrawOrderVO drawOrderVO = buildDrawOrderVO(req, strategyId, takeId, drawResult.getDrawAwardInfo());
        Result result = iActivityPartake.recordDrawOrder(drawOrderVO);
        if(!Constants.ResponseCode.SUCCESS.getCode().equals(result.getCode())){
            return  new DrawProcessResult(result.getCode(),result.getInfo());
        }


        //TODO 异步发奖通过MQ （发送MQ，触发发奖流程）
        InvoiceVO invoiceVO = buildInvoiceVO(drawOrderVO);

        ListenableFuture<SendResult<String, Object>> listenableFuture = lotteryKafkaProducer.send(invoiceVO);

        //MQ异步发奖，针对发奖的结果进行检测，对发奖状态做出变更
        listenableFuture.addCallback(new ListenableFutureCallback<SendResult<String, Object>>() {
            @Override
            public void onFailure(Throwable throwable) {
              //消息投递失败，更改MQ状态值为 2：失败
              iActivityPartake.updateInvoiceMqState(invoiceVO.getuId(),invoiceVO.getOrderId(),Constants.MQState.FAIL.getCode());
            }

            @Override
            public void onSuccess(SendResult<String, Object> stringObjectSendResult) {
                //消息投递成功 更改MQ状态值为 1：成功
                iActivityPartake.updateInvoiceMqState(invoiceVO.getuId(),invoiceVO.getOrderId(),Constants.MQState.COMPLETE.getCode());
            }
        });


        //封装结果返回
        return new DrawProcessResult(Constants.ResponseCode.SUCCESS.getCode(),Constants.ResponseCode.SUCCESS.getInfo(),drawResult.getDrawAwardInfo());
    }


    private InvoiceVO buildInvoiceVO(DrawOrderVO drawOrderVO) {
        InvoiceVO invoiceVO = new InvoiceVO();
        invoiceVO.setuId(drawOrderVO.getuId());
        invoiceVO.setOrderId(drawOrderVO.getOrderId());
        invoiceVO.setAwardId(drawOrderVO.getAwardId());
        invoiceVO.setAwardType(drawOrderVO.getAwardType());
        invoiceVO.setAwardName(drawOrderVO.getAwardName());
        invoiceVO.setAwardContent(drawOrderVO.getAwardContent());
        invoiceVO.setShippingAddress(null);
        invoiceVO.setExtInfo(null);
        return invoiceVO;
    }


    @Override
    public RuleQuantificationCrowdResult doRuleQuantificationCrowd(DecisionMatterReq req) {

        //1:规则量化结果
        EngineResult engineResult = engineFilter.process(req);
        //2:校验量化结果是否成功
        if(!engineResult.isSuccess()){
            return new RuleQuantificationCrowdResult(Constants.ResponseCode.RULE_ERR.getCode(),Constants.ResponseCode.RULE_ERR.getInfo());
        }
        //3:封装返回结果
        RuleQuantificationCrowdResult ruleQuantificationCrowdResult = new RuleQuantificationCrowdResult(Constants.ResponseCode.SUCCESS.getCode(),Constants.ResponseCode.SUCCESS.getInfo());
        ruleQuantificationCrowdResult.setActivityId(Long.parseLong(engineResult.getNodeValue()));
        return ruleQuantificationCrowdResult;
    }


    private DrawOrderVO buildDrawOrderVO(DrawProcessReq req, Long strategyId, Long takeId, DrawAwardInfo drawAwardInfo) {
        long orderId = idGeneratorMap.get(Constants.Ids.SnowFlake).nextId();
        DrawOrderVO drawOrderVO = new DrawOrderVO();
        drawOrderVO.setuId(req.getuId());
        drawOrderVO.setTakeId(takeId);
        drawOrderVO.setActivityId(req.getActivityId());
        drawOrderVO.setOrderId(orderId);
        drawOrderVO.setStrategyId(strategyId);
        drawOrderVO.setStrategyMode(drawAwardInfo.getStrategyMode());
        drawOrderVO.setGrantType(drawAwardInfo.getGrantType());
        drawOrderVO.setGrantDate(drawAwardInfo.getGrantDate());
        drawOrderVO.setGrantState(Constants.GrantState.INIT.getCode());
        drawOrderVO.setAwardId(drawAwardInfo.getAwardId());
        drawOrderVO.setAwardType(drawAwardInfo.getAwardType());
        drawOrderVO.setAwardName(drawAwardInfo.getAwardName());
        drawOrderVO.setAwardContent(drawAwardInfo.getAwardContent());
        return drawOrderVO;
    }

    }
